/*
 *  Project:            timelyRV_v1.x -- a RISCV-32IMC SoC.
 *  Module name:        Memory_Top.
 *  Description:        instr/data memory of timelyRV core.
 *  Last updated date:  2022.06.17.
 *
 *  Communicate with Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright (C) 2021-2022 NUDT.
 *
 *  Noted:
 */

module Memory_Top (
  //* clk & reset;
  input   wire                    i_clk,
  input   wire                    i_rst_n,

  //* interface for configuration;
  input   wire                    i_conf_rden,    //* support read/write
  input   wire                    i_conf_wren,
  input   wire  [          31:0]  i_conf_addr,
  input   wire  [          31:0]  i_conf_wdata,
  output  wire  [          31:0]  o_conf_rdata,   //* rdata is valid after two clk;

  //* interface for PEs (instr.);
  input   wire  [           0:0]  i_instr_req,
  input   wire  [          31:0]  i_instr_addr,
  output  wire  [          31:0]  o_instr_rdata,
  output  wire  [           0:0]  o_instr_rvalid,
  output  wire  [           0:0]  o_instr_gnt,

  //* interface for PEs (data);
  input   wire  [           0:0]  i_data_req,
  input   wire  [          31:0]  i_data_addr,
  input   wire  [           0:0]  i_data_we,
  input   wire  [           3:0]  i_data_be,
  input   wire  [          31:0]  i_data_wdata,
  output  wire  [          31:0]  o_data_rdata,
  output  wire  [           0:0]  o_data_rvalid,
  output  wire  [           0:0]  o_data_gnt,

  //* interface for DMA;
  input   wire  [           0:0]  i_dma_rden,
  input   wire  [           0:0]  i_dma_wren,
  input   wire  [          31:0]  i_dma_addr,
  input   wire  [          31:0]  i_dma_wdata,
  output  wire  [          31:0]  o_dma_rdata,
  output  wire  [           0:0]  o_dma_rvalid,
  output  wire  [           0:0]  o_dma_gnt
);
  assign o_instr_gnt     = 1'b1;
  assign o_data_gnt      = 1'b1;
  assign o_dma_gnt       = 1'b1;

  //====================================================================//
  //*   internal reg/wire/param declarations
  //====================================================================//
  //* wren for sram, i.e., wstrb, means to write which 8b SRAM, in format 
  //*   {sram3_wstrb,sram2_wstrb,...};
  //* addr for sram, in format {sram3_addr,sram2_addr,...};
  //* din for sram, in format {sram3_din,sram2_din,...};
  //* dout for sram, in format {sram3_dout,sram2_dout,...};
  wire  [           3:0]      wren_instr_a, wren_data_a, 
                                wren_instr_b, wren_data_b; 
  wire  [          31:0]      addr_instr_a, addr_instr_b, 
                                addr_data_a,  addr_data_b;
  wire  [          31:0]      din_instr_a,  din_data_a, 
                                din_instr_b,  din_data_b;
  wire  [          31:0]      dout_instr_a, dout_instr_b, 
                                dout_data_a,  dout_data_b;
  reg   [           1:0]      r_temp_instr_valid, r_temp_data_valid;
  reg   [           1:0]      r_temp_dma_valid;
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

  //====================================================================//
  //*   Combine input signals
  //====================================================================//  
  assign  wren_instr_a    = {4{i_conf_wren & (~i_conf_addr[`BIT_CONF])}}; 
  assign  addr_instr_a    = i_conf_addr; 
  assign  din_instr_a     = i_conf_wdata; 
  assign  o_conf_rdata    = dout_instr_a;
  assign  wren_data_a     = {4{(i_conf_wren & i_conf_addr[`BIT_CONF]) | 
                              i_dma_wren[0]}};
  assign  addr_data_a     = (i_conf_wren & i_conf_addr[`BIT_CONF])? i_conf_addr:
                              i_dma_addr[31:0];
  assign  din_data_a      = (i_conf_wren & i_conf_addr[`BIT_CONF])? i_conf_wdata:
                              i_dma_wdata[31:0];
  assign  o_dma_rdata     = dout_data_a;

  assign  wren_instr_b    = 4'b0; 
  assign  addr_instr_b    = i_instr_addr;
  assign  din_instr_b     = 32'b0;
  assign  wren_data_b     = i_data_be & {4{i_data_req & i_data_we}};
  assign  addr_data_b     = i_data_addr;
  assign  din_data_b      = i_data_wdata;
  assign  o_instr_rdata   = dout_instr_b;
  assign  o_data_rdata    = dout_data_b;
  assign  o_instr_rvalid  = r_temp_instr_valid[1];
  assign  o_data_rvalid   = r_temp_data_valid[1];
  assign  o_dma_rvalid    = r_temp_dma_valid[1];
  //* maintain valid;
  always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n) begin
      r_temp_instr_valid  <= 2'b0;
      r_temp_data_valid   <= 2'b0;
      r_temp_dma_valid    <= 2'b0;
    end
    else begin
      r_temp_instr_valid  <= {r_temp_instr_valid[0],i_instr_req};
      r_temp_data_valid   <= {r_temp_data_valid[0],i_data_req};
      r_temp_dma_valid    <= {r_temp_dma_valid[0],i_dma_rden|i_dma_wren};
    end
  end
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//
    
  //====================================================================//
  //*   32KB Instr/Data RAM
  //====================================================================//
  //* instr;
  memory_part_64KB instr_mem(
    .clk    (i_clk                          ),
    .rst_n  (i_rst_n                        ),
    .wea    (wren_instr_a                   ),  
    .addra  (addr_instr_a                   ),
    .dina   (din_instr_a                    ),
    .douta  (dout_instr_a                   ),
    .web    (wren_instr_b                   ),  
    .addrb  (addr_instr_b                   ),
    .dinb   (din_instr_b                    ),
    .doutb  (dout_instr_b                   )
  );
  //* data;
  memory_part_64KB data_mem(
    .clk    (i_clk                          ),
    .rst_n  (i_rst_n                        ),
    .wea    (wren_data_a                    ),  
    .addra  (addr_data_a                    ),
    .dina   (din_data_a                     ),
    .douta  (dout_data_a                    ),
    .web    (wren_data_b                    ),  
    .addrb  (addr_data_b                    ),
    .dinb   (din_data_b                     ),
    .doutb  (dout_data_b                    )
  );
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

endmodule